package top.lc951.myglide.load.engine.bitmap_recycle;

import android.graphics.Bitmap;
import android.os.Build;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;

import java.util.Arrays;

import top.lc951.myglide.util.Synthetic;
import top.lc951.myglide.util.Util;

/**
 * Keys {@link android.graphics.Bitmap Bitmaps} using both {@link
 * android.graphics.Bitmap#getAllocationByteCount()} and the {@link android.graphics.Bitmap.Config}
 * returned from {@link android.graphics.Bitmap#getConfig()}.
 *
 * <p>Using both the config and the byte size allows us to safely re-use a greater variety of {@link
 * android.graphics.Bitmap Bitmaps}, which increases the hit rate of the pool and therefore the
 * performance of applications. This class works around #301 by only allowing re-use of {@link
 * android.graphics.Bitmap Bitmaps} with a matching number of bytes per pixel.
 */
@RequiresApi(Build.VERSION_CODES.KITKAT)
public class SizeConfigStrategy implements LruPoolStrategy{
    private static final int MAX_SIZE_MULTIPLE = 8;
    private static final Bitmap.Config[] ARGB_8888_IN_CONFIGS;
    static {
        Bitmap.Config[] result =
                new Bitmap.Config[] {
                        Bitmap.Config.ARGB_8888,
                        // The value returned by Bitmaps with the hidden Bitmap config.
                        null,
                };
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            result = Arrays.copyOf(result, result.length + 1);
            result[result.length - 1] = Bitmap.Config.RGBA_F16;
        }
        ARGB_8888_IN_CONFIGS = result;
    }

    // TODO: 2/10/22 图片常用的编码格式
    private static final Bitmap.Config[] RGBA_F16_IN_CONFIGS = ARGB_8888_IN_CONFIGS;
    // We probably could allow ARGB_4444 and RGB_565 to decode into each other, but ARGB_4444 is
    // deprecated and we'd rather be safe.
    private static final Bitmap.Config[] RGB_565_IN_CONFIGS =
            new Bitmap.Config[] {Bitmap.Config.RGB_565};
    private static final Bitmap.Config[] ARGB_4444_IN_CONFIGS =
            new Bitmap.Config[] {Bitmap.Config.ARGB_4444};
    private static final Bitmap.Config[] ALPHA_8_IN_CONFIGS =
            new Bitmap.Config[] {Bitmap.Config.ALPHA_8};

    private final KeyPool keyPool = new KeyPool();


    @Override
    public void put(Bitmap bitmap) {

    }

    @Nullable
    @Override
    public Bitmap get(int width, int height, Bitmap.Config config) {
        return null;
    }

    @Nullable
    @Override
    public Bitmap removeLast() {
        return null;
    }

    @Override
    public String logBitmap(Bitmap bitmap) {
        return null;
    }

    @Override
    public String logBitmap(int width, int height, Bitmap.Config config) {
        return null;
    }

    @Override
    public int getSize(Bitmap bitmap) {
        return 0;
    }

    @VisibleForTesting
    static class KeyPool extends BaseKeyPool<Key> {

        public Key get(int size, Bitmap.Config config) {
            Key result = get();
            result.init(size, config);
            return result;
        }

        @Override
        protected Key create() {
            return new Key(this);
        }
    }
    @VisibleForTesting
    static final class Key implements Poolable {
        private final KeyPool pool;
        @Synthetic int size;
        private Bitmap.Config config;

        public Key(KeyPool pool) {
            this.pool = pool;
        }

        @VisibleForTesting
        Key(KeyPool pool, int size, Bitmap.Config config) {
            this(pool);
            init(size, config);
        }

        public void init(int size, Bitmap.Config config) {
            this.size = size;
            this.config = config;
        }

        @Override
        public void offer() {
            pool.offer(this);
        }

        @Override
        public String toString() {
            return getBitmapString(size, config);
        }

        @Override
        public boolean equals(Object o) {
            if (o instanceof Key) {
                Key other = (Key) o;
                return size == other.size && Util.bothNullOrEqual(config, other.config);
            }
            return false;
        }

        @Override
        public int hashCode() {
            int result = size;
            result = 31 * result + (config != null ? config.hashCode() : 0);
            return result;
        }
    }

    @Synthetic
    static String getBitmapString(int size, Bitmap.Config config) {
        return "[" + size + "](" + config + ")";
    }


    private static Bitmap.Config[] getInConfigs(Bitmap.Config requested) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (Bitmap.Config.RGBA_F16.equals(requested)) { // NOPMD - Avoid short circuiting sdk checks.
                return RGBA_F16_IN_CONFIGS;
            }
        }

        switch (requested) {
            case ARGB_8888:
                return ARGB_8888_IN_CONFIGS;
            case RGB_565:
                return RGB_565_IN_CONFIGS;
            case ARGB_4444:
                return ARGB_4444_IN_CONFIGS;
            case ALPHA_8:
                return ALPHA_8_IN_CONFIGS;
            default:
                return new Bitmap.Config[] {requested};
        }
    }
}
